package drytools.site.css;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Node;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.css.CSSStyleRule;
import org.w3c.dom.traversal.NodeFilter;

import com.icesoft.faces.context.DOMContext;
import com.sun.org.apache.xerces.internal.dom.DocumentImpl;
import com.sun.org.apache.xerces.internal.dom.NodeIteratorImpl;
import com.sun.org.apache.xpath.internal.XPathAPI;

import drytools.site.model.AllElements;

public class CSSTools {
	String currentInLine;
	List<String> stylesNamesInCurrentView;
	EditableCSSList editableCSSList;
	ColorsSelections colorsSelections;
	//String idOfExampleMaster;
	
	public ColorsSelections getColorsSelections() {
		if (colorsSelections == null) {
			colorsSelections = new ColorsSelections();
		}
		return colorsSelections;
	}

	public void setColorsSelections(ColorsSelections colorsSelections) {
		this.colorsSelections = colorsSelections;
	}

	public EditableCSSList getEditableCSSList() {
		if (editableCSSList == null) {
			editableCSSList = new EditableCSSList();
		}
		return editableCSSList;
	}

	public void reset() {
		currentInLine = null;
		stylesNamesInCurrentView = null;
		editableCSSList = null;
		//scanStylesNamesInCurrentView();
	}
	
	private boolean isCSSRuleMatch(String selectorString, String styleName) {
		selectorString = selectorString.trim();
		String[] commaSeparated = selectorString.split(",");
		for (int i = 0; i < commaSeparated.length; i++) {
			String rule = commaSeparated[i].trim();
			if (rule.startsWith("*." + styleName)) {
				return true;
			}
		}
		return false;
	}

	public void scanStylesNamesInCurrentView() {
		getEditableCSSList().setEditableRules(new ArrayList<EditableCSSRule>());
		getEditableCSSList().getRulesMappedByName().clear();

		Map<String, String> justToCheckUnicness = new HashMap<String, String>();
		List<String> stylesNames = getStylesNamesInCurrentView();
		for (String styleName : stylesNames) {
			// find matching rule...

			for (CSSStyleRule cssRule : getEditableCSSList().getAllKnownRules()) {
				if (isCSSRuleMatch(cssRule.getSelectorText(), styleName)) {
					EditableCSSRule editableRule = new EditableCSSRule();
					editableRule.setSelectorsString(cssRule.getSelectorText());

					CSSStyleDeclaration styleDeclaration = cssRule.getStyle();

					for (int j = 0; j < styleDeclaration.getLength(); j++) {
						String propertyName = styleDeclaration.item(j);
						String propertyValue = styleDeclaration
								.getPropertyValue(propertyName);
						// System.out.println("" + propertyName + " = "
						// + propertyValue);

						editableRule.getProperties().add(
								new EditableCSSProperty(propertyName,
										propertyValue));

					}

					if (!justToCheckUnicness.containsKey(cssRule
							.getSelectorText())) {
						getEditableCSSList().getEditableRules().add(
								editableRule);
						getEditableCSSList().addRuleToMapByName(styleName,
								editableRule);
						justToCheckUnicness.put(cssRule.getSelectorText(),
								cssRule.getSelectorText());
					}

				}
			}

		}
	}

	public void save() {

	}

	public void changeStyle(ActionEvent event) throws AbortProcessingException {
		currentInLine = null;
	}

	public String getCurrentInLine() {
		if (currentInLine == null) {
			StringBuffer res = new StringBuffer();
			res.append("<style>\n");
			res.append("\n");
			List<EditableCSSRule> editableRules = getEditableCSSList()
					.getEditableRules();
			for (EditableCSSRule editableCSSRule : editableRules) {
				res.append("div#exampleMaster "+editableCSSRule.getSelectorsString()).append(" {\n");
				for (EditableCSSProperty property : editableCSSRule
						.getProperties()) {
					res.append(property.getName()).append(" : ").append(
							property.getValue()).append(";\n");
				}

				res.append("\n}\n");
			}
			res.append("</style>\n");
			currentInLine = res.toString();
			//System.out.println(currentInLine);
		}
		return currentInLine;
	}

	public void setCurrentInLine(String currentInLine) {
		this.currentInLine = currentInLine;
	}

	public void cancel() {

	}

	public List<String> getStylesNamesInCurrentView() {
		if (stylesNamesInCurrentView == null) {
			// System.out.println("in getStylesNamesInCurrentView");

			List<String> res = new ArrayList<String>();
			Map<String, String> map = new HashMap<String, String>();
			UIViewRoot viewRoot = FacesContext.getCurrentInstance()
					.getViewRoot();
			DOMContext domContext = DOMContext.getDOMContext(FacesContext
					.getCurrentInstance(), viewRoot);
			DocumentImpl document = (DocumentImpl) domContext.getDocument();
			Node root = document.getLastChild();

			String xpath = "//*[contains(@id,'exampleMaster')]";
			try {
				Node exampleNode = XPathAPI.selectSingleNode(document, xpath);
				//idOfExampleMaster = exampleNode.getAttributes().getNamedItem("id").getNodeValue();
				
				// Node rootNode = domContext.getRootNode();
				AllElements allelements = new AllElements();

				// create an object of the NodeIterator implementation class
				NodeIteratorImpl iterator = (NodeIteratorImpl) document
						.createNodeIterator(exampleNode,
								NodeFilter.SHOW_ELEMENT,
								(NodeFilter) allelements, true);

				Node n = iterator.nextNode(); // skip first node, its container
				while ((n = iterator.nextNode()) != null) {

					if (n.getAttributes().getNamedItem("class") != null) {
						Node named = n.getAttributes().getNamedItem("class");
						String name = named.getNodeValue().trim();
						if (name.indexOf(' ') != -1) {
							String[] names = name.split(" ");
							for (int i = 0; i < names.length; i++) {
								String subName = names[i].trim();
								if (subName.length() > 0 && map.containsKey(subName)) {
									continue;
								}
								map.put(subName, subName);
								res.add(subName);
							}
						} else {
							if (map.containsKey(name)) {
								continue;
							}
							map.put(name, name);
							res.add(name);
						}
					}
				}
				
				
			} catch (TransformerException e) {
				e.printStackTrace();
			}

			stylesNamesInCurrentView = res;
			
			scanStylesNamesInCurrentView();
		}
		return stylesNamesInCurrentView;
	}
}
